home *** CD-ROM | disk | FTP | other *** search
- /*
- File: AIFF.c
-
- Contains: Routine demonstrating how to parse AIFF sound files.
-
- Written by: Mark Cookson
-
- Copyright: Copyright © 1996-1999 by Apple Computer, Inc., All Rights Reserved.
-
- You may incorporate this Apple sample source code into your program(s) without
- restriction. This Apple sample source code has been provided "AS IS" and the
- responsibility for its operation is yours. You are not permitted to redistribute
- this Apple sample source code as "Apple sample source code" after having made
- changes. If you're going to re-distribute the source, we require that you make
- it clear in the source that the code was descended from Apple sample source
- code, but that you've made changes.
-
- Change History (most recent first):
- 8/31/1999 Karl Groethe Updated for Metrowerks Codewarror Pro 2.1
-
-
- */
-
- #include "MyAIFF.h"
-
- /*
- need to substitute this code where using long doubles
-
- typedef struct myLongDouble {
- double firstHalf;
- double secondHalf;
- } myLongDouble;
-
- */
-
- /* Given an AIFF File gets the sample rate and other relavent pieces of information.
- This has been modified from its orignal form found in the Develop 11 MultiBuffer source. */
- /*-----------------------------------------------------------------------*/
- OSErr ASoundGetAIFFHeader (SoundInfoPtr theSoundInfo,
- long *dataStart,
- long *length)
- /*-----------------------------------------------------------------------*/
- {
- ChunkTemplatePtr chunkTemplate = nil; /* ...for ease of access */
- unsigned long type = kInit;
- long filePosition = kInit,
- byteCount = kInit;
- Fixed sampleRate = kInit;
- unsigned short chunkFlags = kInit; /* remember chunks we've seen */
- OSErr err = noErr;
- char chunkBuffer[kChunkBufferSize];
-
- *dataStart = kInit;
-
- /* Parse the AIFF (or AIFC) header */
-
- do {
- /* Position ourselves at the beginning of the next chunk and read in
- a hunk-o-data... */
- err = SetFPos (theSoundInfo->refNum, fsFromStart, filePosition);
- if (err != noErr) {
- DebugPrint ("\pSetFPos failed!");
- break;
- }
-
- byteCount = kChunkBufferSize;
- err = FSRead (theSoundInfo->refNum, &byteCount, chunkBuffer); /* read a chunk */
- if ((err != noErr) && (err != eofErr)) {
- DebugPrint ("\pFSRead failed!");
- break;
- }
-
- /* Now, position the template over the data... */
- chunkTemplate = (ChunkTemplatePtr) chunkBuffer;
-
- /* assume a failure and break out of the do {} while loop if the next case isn't found.
- if the case is found and no other error is detected, then each case needs to set noErr */
- err = badFileFormat;
- switch (chunkTemplate->generic.ckID) {
- case FORMID: /* Format Version Chunk? */
- /* make sure that this is a standard, noncompressed AIFF file. */
- if ((chunkFlags & kFORM) == false) { /* see if this chunk already exists */
- chunkFlags |= kFORM; /* otherwise mark it found */
- *length = chunkTemplate->container.ckSize;
- filePosition += sizeof (ContainerChunk); /* Can't use ckSize because it's the size of the file, not this header */
- type = chunkTemplate->container.formType;
- err = noErr;
- }
- break;
- case FormatVersionID: /* Format Version Chunk? */
- if ((chunkFlags & kFormatVersion) == false) { /* see if this chunk already exists */
- chunkFlags |= kFormatVersion; /* otherwise mark it found */
- filePosition += chunkTemplate->formatVersion.ckSize + kChunkHeaderSize; /* calculate next chunk's position */
- if (chunkTemplate->formatVersion.timestamp != AIFCVersion1) {
- err = kUnknownFormat;
- }
- else {
- err = noErr;
- }
- }
- break;
- case CommonID:
- if ((chunkFlags & kCommon) == false) { /* see if this chunk already exists */
- long double tempLD = 0.0;
-
- chunkFlags |= kCommon; /* otherwise mark it found */
- filePosition += chunkTemplate->common.ckSize + kChunkHeaderSize; /* calculate next chunk's position */
-
- #ifdef powerc
- x80told (&(chunkTemplate->common.sampleRate), &tempLD);
- #else
- tempLD = chunkTemplate->common.sampleRate;
- #endif
- sampleRate = ASoundLongDoubleToFix (tempLD);
-
- if (type == AIFCID) {
- err = SetupDBHeader (theSoundInfo,
- sampleRate,
- chunkTemplate->common.sampleSize,
- chunkTemplate->common.numChannels,
- fixedCompression,
- chunkTemplate->extCommon.compressionType);
- theSoundInfo->needsMasking = false;
- }
- else {
- err = SetupDBHeader (theSoundInfo,
- sampleRate,
- chunkTemplate->common.sampleSize,
- chunkTemplate->common.numChannels,
- notCompressed,
- NoneType);
- if (chunkTemplate->common.sampleSize == kSixteen) {
- theSoundInfo->needsMasking = false;
- }
- else {
- theSoundInfo->needsMasking = true;
- }
- }
- }
- break;
- case SoundDataID:
- if ((chunkFlags & kSoundData) == false) { /* see if this chunk already exists */
-
- /* Let's remember where the Sound Data starts, so we can find the position in the file later.
- The mark will be positioned at the beginning of the chunk, so move 16 bytes past to get past
- the header information to the data. */
- *dataStart = filePosition + 16;
- chunkFlags |= kSoundData; /* otherwise mark it found */
- filePosition += chunkTemplate->soundData.ckSize + kChunkHeaderSize; /* calculate next chunk's position */
- err = noErr;
- }
- break;
- /*
- The following list of chunks we don't care about, so we'll just skip over them.
- */
- case MarkerID:
- if ((chunkFlags & kMarker) == false) { /* see if this chunk already exists */
- chunkFlags |= kMarker; /* otherwise mark it found */
- filePosition += chunkTemplate->marker.ckSize + kChunkHeaderSize; /* calculate next chunk's position */
- err = noErr;
- }
- break;
- case CommentID:
- if ((chunkFlags & kComment) == false) { /* see if this chunk already exists */
- chunkFlags |= kComment; /* otherwise mark it found */
- filePosition += chunkTemplate->marker.ckSize + kChunkHeaderSize; /* calculate next chunk's position */
- err = noErr;
- }
- break;
- case InstrumentID:
- if ((chunkFlags & kInstrument) == false) { /* see if this chunk already exists */
- chunkFlags |= kInstrument; /* otherwise mark it found */
- filePosition += chunkTemplate->instrument.ckSize + kChunkHeaderSize; /* calculate next chunk's position */
- err = noErr;
- }
- break;
- case MIDIDataID:
- if ((chunkFlags & kMIDIData) == false) { /* see if this chunk already exists */
- chunkFlags |= kMIDIData; /* otherwise mark it found */
- filePosition += chunkTemplate->midiData.ckSize + kChunkHeaderSize; /* calculate next chunk's position */
- err = noErr;
- }
- break;
- case AudioRecordingID:
- if ((chunkFlags & kAudioRecording) == false) { /* see if this chunk already exists */
- chunkFlags |= kAudioRecording; /* otherwise mark it found */
- filePosition += chunkTemplate->audioRecording.ckSize + kChunkHeaderSize; /* calculate next chunk's position */
- err = noErr;
- }
- break;
- case ApplicationSpecificID:
- if ((chunkFlags & kApplicationSpecific) == false) { /* see if this chunk already exists */
- chunkFlags |= kApplicationSpecific; /* otherwise mark it found */
- filePosition += chunkTemplate->generic.ckSize + kChunkHeaderSize; /* calculate next chunk's position */
- err = noErr;
- }
- break;
- case NameID:
- if ((chunkFlags & kName) == false) { /* see if this chunk already exists */
- chunkFlags |= kName; /* otherwise mark it found */
- filePosition += chunkTemplate->generic.ckSize + kChunkHeaderSize; /* calculate next chunk's position */
- err = noErr;
- }
- break;
- case AuthorID:
- if ((chunkFlags & kAuthor) == false) { /* see if this chunk already exists */
- chunkFlags |= kAuthor; /* otherwise mark it found */
- filePosition += chunkTemplate->generic.ckSize + kChunkHeaderSize; /* calculate next chunk's position */
- err = noErr;
- }
- break;
- case CopyrightID:
- if ((chunkFlags & kCopyright) == false) { /* see if this chunk already exists */
- chunkFlags |= kCopyright; /* otherwise mark it found */
- filePosition += chunkTemplate->generic.ckSize + kChunkHeaderSize; /* calculate next chunk's position */
- err = noErr;
- }
- break;
- case AnnotationID:
- if ((chunkFlags & kAnnotation) == false) { /* see if this chunk already exists */
- chunkFlags |= kAnnotation; /* otherwise mark it found */
- filePosition += chunkTemplate->generic.ckSize + kChunkHeaderSize; /* calculate next chunk's position */
- err = noErr;
- }
- break;
- default : /* Unrecognized?? croak. */
- DebugPrint ("\pran into an undefined chunk!!");
-
- /* If we hit an unrecognized chunk, clear chunkFlags to drop out of the loop
- with the assumed error code. */
- chunkFlags = kInit;
- break;
- }
-
- /* We're only done when the the FORM, FormatVersion, Common and Sound Data chunks. This is only
- true of this incarnation - your needs may vary, so you'll have to modify the following statement
- accordingly...
- I know, this clause is a pain in the ass: what it really says is this:
- As long as we have a FORM Chunk and we don't have all of the {Formatversion, Common, SoundData} chunks
- keep going... AND we haven't gotten an error from the file system. */
- } while (stillMoreDataToRead);
-
- if (err != noErr) {
- DebugPrint ("\pError in ASoundGetAIFFHeader");
- }
-
- return err;
- }
-